#include <iostream>
#include <stdexcept>
#include "sample.hpp"

namespace sample {
namespace autosar {


static constexpr std::int32_t RETURN_0 { 0 };
static constexpr std::int32_t RETURN_0U { 0U };

/* Rule A0-1-1 (required, implementation, automated)
 * A project shall not contain instances of non-volatile variables being
 * given values that are not subsequently used.
 */

std::uint32_t func_A0_1_2_helper() noexcept
{
    return RETURN_0;
}

/* Rule A0-1-2 (required, implementation, automated)
 * The value returned by a function having a non-void return type that is not
 * an overloaded operator shall be used.
 */
void func_A0_1_2() noexcept
{
    func_A0_1_2_helper();  // Non-compliant
    static_cast<void>(func_A0_1_2_helper());  // Compliant, be be discarded intentionally
}

/* Rule A0-1-3 (required, implementation, automated)
 * Every function defined in an anonymous namespace,
 * or static function with internal linkage,
 * or private member function shall be used.
 */

/* Rule A0-1-4 (required, implementation, automated)
 * There shall be no unused named parameters in non-virtual functions.
 */

/* Rule A0-1-5 (required, implementation, automated)
 * There shall be no unused named parameters in the set of parameters for
 * a virtual function and all the functions that override it.
 */

/* Rule A0-1-6 (advisory, implementation, automated)
 * There should be no unused type declarations.
 */

/* Rule A0-4-1 (required, infrastructure / toolchain, non-automated)
 * Floating-point implementation shall comply with IEEE 754 standard.
 */

/* Rule A0-4-2 (required, implementation, automated)
 * Type long double shall not be used.
 */

/* Rule A0-4-3 (required, toolchain, automated)
 * The implementations in the chosen compiler shall strictly
 * comply with the C++14 Language Standard.
 */

/* Rule A0-4-4 (required, implementation, partially automated)
 * Range, domain and pole errors shall be checked when using math functions.
 */

/* Rule A1-1-1 (required, implementation, automated)
 * All code shall conform to ISO/IEC 14882:2014 - 
 * Programming Language C++ and shall not use deprecated features.
 */

/* Rule A1-1-2 (required, implementation / toolchain, non-automated)
 * A warning level of the compilation process shall be set in compliance with project policies.
 */

/* Rule A1-1-3 (required, toolchain, non-automated)
 * An optimization option that disregards strict standard compliance
 * shall not be turned on in the chosen compiler.
 */

/* Rule A1-2-1 (required, toolchain, non-automated)
 * When using a compiler toolchain (including preprocessor, compiler itself, linker, C++ standard libraries)
 * in safety-related software, the tool confidence level (TCL) shall be determined.
 * In case of TCL2 or TCL3, the compiler shall undergo a "Qualification of a software tool",
 * as per ISO 26262-8.11.4.6 [6].
 */

/* Rule A1-4-1 (required, implementation / verification, non-automated)
 * Code metrics and their valid boundaries shall be defined and code shall comply with defined boundaries of code metrics.
 */

/* Rule A1-4-3 (advisory, implementation, automated)
 * All code should compile free of compiler warnings.
 */

/* Rule A2-3-1 (required, architecture / design / implementation, automated)
 * Only those characters specified in the C++ Language Standard basic source character set shall be used in the source code.
 */

/* Rule A2-5-1 (required, implementation, automated)
 * Trigraphs shall not be used.
 */

/* Rule A2-5-2 (required, implementation, automated)
 * Digraphs shall not be used.
 */

/* Rule A2-7-1 (required, implementation, automated)
 * The character \ shall not occur as a last character of a C++ comment.
 */

/* Rule A2-7-2 (required, implementation, non-automated)
 * Sections of code shall not be "commented out".
 */

/* Rule A2-7-3 (required, implementation, automated)
 * All declarations of "user-defined" types, static and non-static data members, functions and methods shall be preceded by documentation.
 */
std::int32_t func_A2_7_3(std::int32_t const input1, std::int64_t const input2) noexcept(false)
{
    if (input2 > static_cast<std::int64_t>(input1))
    {
        throw std::runtime_error("input2 is larger than input1");
    }

    return input1;
}

/* Rule A7-4-1 (required, implementation, automated)
 * The asm declaration shall not be used.
 */

/* Rule A7-5-1 (required, implementation, automated)
 * A function shall not return a reference or a pointer to a parameter
 * that is passed by reference to const.
 */
const A& func_A7_5_1_a(A const & _ref) noexcept
{
    return _ref; // Non-compliant
}
/* non-compliant A8-4-4 and A8-4-8 */
const A& func_A7_5_1_b(A & _ref) noexcept
{
    static constexpr std::int32_t ID_5 { 5 };
    _ref.SetID(ID_5);
    return _ref;
}
const A* func_A7_5_1_c(A const & _ref) noexcept
{
    return &_ref; // Non-compliant
}
/* non-compliant A8-4-4 and A8-4-8 */
const A* func_A7_5_1_d(A & _ref) noexcept
{
    static constexpr std::int32_t ID_5 { 5 };
    _ref.SetID(ID_5);
    return &_ref;
}
void func_A7_5_1() noexcept
{
    /* all of the following statements are non-compliant
     * in other words, NEVER return a reference from a function
     */
    A var_a {};
    A const & ref1 { func_A7_5_1_a(var_a) };
    A const & ref2 { func_A7_5_1_b(var_a) };
    A const * const ptr1 { func_A7_5_1_c(var_a) };
    A const * const ptr2 { func_A7_5_1_d(var_a) };

    A const & ref3 { func_A7_5_1_a(A{}) };
    A const * const ptr3 { func_A7_5_1_c(A{}) };

    static_cast<void>(ref1.GetID());
    static_cast<void>(ref2.GetID());
    static_cast<void>(ref3.GetID()); // Non-compliant A3-8-1
    static_cast<void>(ptr1->GetID());
    static_cast<void>(ptr2->GetID());
    static_cast<void>(ptr3->GetID()); // Non-compliant A3-8-1
}

/* Rule A7-5-2 (required, implementation, automated)
 * Functions shall not call themselves, either directly or indirectly.
 */

/* Rule A7-6-1 (required, implementation, automated)
 * Functions declared with the [[noreturn]] attribute shall not return.
 * e.g. [[noreturn]] void func_A7_6_1() noexcept(false);
 */

/* Rule A8-2-1 (required, implementation, automated)
 * When declaring function templates, the trailing return type syntax
 * shall be used if the return type depends on the type of parameters.
 */
template <typename T>
typename B<T>::Type B<T>::f(T const&) noexcept // Non-compliant
{
    return RETURN_0;
}
template <typename T>
auto B<T>::g(T const&) noexcept -> Type // Compliant
{
    return RETURN_0;
}

/* Rule A8-4-1 (required, implementation, automated)
 * Functions shall not be defined using the ellipsis notation.
 */
void func_A8_4_1_a(char const * const _format, ...) noexcept // Non-compliant - variadic arguments are used
{
// ...
}
template <typename First, typename... Rest>
void func_A8_4_1_b(First const & _first, Rest const &... _args) noexcept // Compliant
{
// ...
}

/* Rule A8-4-2 (required, implementation, automated)
 * All exit paths from a function with non-void return type
 * shall have an explicit return statement with an expression.
 */

/* Rule A8-4-3 (advisory, design, non-automated)
 * Common ways of passing parameters should be used.
 * |==========================================================================|
 * |         | cheap to copy or move only | cheap to move | expensive to move |
 * |    in   |           f(X)             |           f(X const &)            |
 * |--------------------------------------------------------------------------|
 * |  in/out |                            f(X &)                              |
 * |--------------------------------------------------------------------------|
 * |   out   |                      X f()                 |      f(X &)       |
 * |--------------------------------------------------------------------------|
 * | consume |                           f(X &&)                              |
 * |--------------------------------------------------------------------------|
 * | forward |                template<typename T> f(T &&)                    |
 * |==========================================================================|
 */

/* Rule A8-4-4 (advisory, design, automated)
 * Multiple output values from a function
 * should be returned as a struct or tuple.
 */
std::int32_t func_A8_4_4_a(std::int32_t const _dividend
                         , std::int32_t const _divisor
                         , std::int32_t & _remainder) // Non-compliant, remainder returned as the output parameter
{
    _remainder = _dividend % _divisor;
    return _dividend / _divisor;
}
std::tuple<std::int32_t, std::int32_t> func_A8_4_4_b(std::int32_t const _dividend
                                                   , std::int32_t const _divisor)
{
    return std::make_tuple(_dividend/_divisor, _dividend % _divisor);
}







/* ================================================================================== */
void A::SetID(std::int32_t const _id) noexcept
{
    mId = _id;
}
std::int32_t A::GetID() const noexcept
{
    return mId;
}

}
}
